﻿/**
 * @file Socket.cc
 * @brief Socket封装
 * $Id: Socket.cc 13 2011-01-01 11:48:27Z tonyjobmails $
 * $Date: 2011-01-01 11:48:27 +0000 (Sat, 01 Jan 2011) $
 * $Author: tonyjobmails $
 * $Revision: 13 $
 */

#include <sys/epoll.h>
#include <assert.h>
#include <fcntl.h>
#include <zlib.h>
#include <strings.h>
#include "Log.h"
#include "Socket.h"

#ifdef _TOTO_DEBUG
#include <vector>
#endif

Socket::Socket(int sockfd)
{
	assert(this->_M_sockfd != -1);

	this->_M_sockfd = sockfd;

	socklen_t addrLen = sizeof(this->_M_addr);
	assert(::getpeername(this->_M_sockfd, (struct sockaddr*)&this->_M_addr, &addrLen) == 0);

	socklen_t localAddrLen = sizeof(this->_M_local_addr);
	assert(::getsockname(this->_M_sockfd, (struct sockaddr*)&this->_M_local_addr, &localAddrLen) == 0);

#ifdef _TOTO_DEBUG
	log::_DEBUG_LOG("套接口远端地址(%s)", ::inet_ntoa(this->_M_addr.sin_addr));
	log::_DEBUG_LOG("套接口本地地址(%s)", ::inet_ntoa(this->_M_local_addr.sin_addr));
#endif

	/// 防止重启端口不可用
	socklen_t len = sizeof(int);
	int opt = 0;
	assert(setsockopt(this->_M_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len) == 0);

	setNonblock();
}

Socket::~Socket()
{
	shutdown(this->_M_sockfd, SHUT_RDWR);
	close(this->_M_sockfd);
}

/**
 * @brief 设置套接口为非阻塞模式
 */
void Socket::setNonblock()
{
	int flags = 0;
	flags = fcntl(this->_M_sockfd, F_GETFL, 0);
	int retcode = fcntl(this->_M_sockfd, F_SETFL, flags | O_NONBLOCK);

	if(retcode == -1)
		log::_ERROR_LOG("非阻塞设置错误，%s", __PRETTY_FUNCTION__);
}

/**
 * @brief 封包
 * @in：输入数据
 * @len：输入的安全长度
 * @out：输出数据
 * @return：输出长度
 */
unsigned int Socket::packet(const unsigned char *in, const unsigned int len, StcByteBuff &buffer)
{
	if(!in || !len)
	{
		log::_ERROR_LOG("封包错误，输入数据错误，%s", __PRETTY_FUNCTION__);
		return 0;
	}

	uLongf destLen = MIN_ZIP_LEN(len);

	switch(compress(&(buffer._ptr()[_PACKET_HEAD_SIZE]), &destLen, static_cast<const Bytef*>(in), len))
	{
		case Z_OK:
			break;
		case Z_MEM_ERROR:
			log::_ERROR_LOG("压缩错误 Z_MEM_ERROR，%s", __PRETTY_FUNCTION__);
			return 0;
		case Z_BUF_ERROR:
			log::_ERROR_LOG("压缩错误 Z_BUF_ERROR，destLen(%u)，%s", destLen, __PRETTY_FUNCTION__);
			return 0;
		default:
			return 0;
	}

	*((unsigned int*)buffer._ptr()) = destLen | _PACKET_ZIP_FLAG;

	return destLen + _PACKET_HEAD_SIZE;
}

/**
 * @brief 拆包
 * @in：输入数据
 * @len：输入的安全长度
 * @out：输出数据
 * @return：输出长度
 */
unsigned int Socket::unpacket(const unsigned char *in, const unsigned int len, StcByteBuff &buffer)
{
	if(!in || !len)
	{
		log::_ERROR_LOG("拆包错误，输入数据有错误，%s", __PRETTY_FUNCTION__);
		return 0;
	}

	if(len < _PACKET_HEAD_SIZE)
	{
		log::_ERROR_LOG("拆包错误，包头长度小于(%u)，%s", _PACKET_HEAD_SIZE, __PRETTY_FUNCTION__);
		return 0;
	}

	unsigned int packetSize = this->packetDataLen(in);

	if(len < packetSize + _PACKET_HEAD_SIZE)
	{
		log::_ERROR_LOG("拆包错误，包头长度错误，%s", __PRETTY_FUNCTION__);
		return 0;
	}

	if(*((unsigned int*)in) | _PACKET_ZIP_FLAG)
	{
		uLongf destLen = 0;
		switch(uncompress(&(buffer._ptr()[_PACKET_HEAD_SIZE]), &destLen, static_cast<const Bytef*>(&(in[_PACKET_HEAD_SIZE])), packetSize))
		{
			case Z_OK:
				break;
			case Z_MEM_ERROR:
				log::_ERROR_LOG("解压错误 Z_MEM_ERROR，%s", __PRETTY_FUNCTION__);
				break;
			case Z_BUF_ERROR:
				log::_ERROR_LOG("解压错误 Z_BUF_ERROR，%s", __PRETTY_FUNCTION__);
				break;
			default:
				break;
		}
		return destLen;
	}
	else
	{
		bcopy(in, &(buffer._ptr()[_PACKET_HEAD_SIZE]), packetSize);
		return packetSize;
	}
}

/**
 * @brief 得到包长
 * @param packet：数据包指针
 * @return：返回包长度
 */
unsigned int Socket::packetLen(const unsigned char *packet)
{
	return (packet ? *((unsigned int *)packet)&_PACKET_LEN_MASK : 0);
}


/**
 * @brief 得到数据部分长度
 * @param packet：数据包指针
 * @return：返回数据长度
 */
unsigned int Socket::packetDataLen(const unsigned char *packet)
{
	unsigned int ret = this->packetLen(packet);
	return ((ret >= _PACKET_HEAD_SIZE) ? ret - _PACKET_HEAD_SIZE : 0);
}

/**
 * @brief 发送缓冲区数据
 * @return：返回发送的数据长度（-1：出错）
 */
int Socket::send_buff()
{
	/// 发送发送缓冲区中的数据
	int retcode = ::send(this->_M_sockfd, this->_M_wr_buff.rd_ptr(), this->_M_wr_buff.rd_size(), MSG_NOSIGNAL);
	if(retcode == -1)
	{
		log::_ERROR_LOG("发送数据时出错，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	/// 整理发送缓冲区中的读取端
	this->_M_wr_buff.rd_shiftout(retcode);

#ifdef _TOTO_DEBUG
	log::_DEBUG_LOG("数据缓冲区中数据到socket成功，发送数据 [%u] 字节", retcode);
#endif

	return retcode;
}

/**
 * @brief 发送数据到缓冲
 * @param data：要发送的数据
 * @param size：要发送的数据长度
 * @return：发送到缓冲区的数据长度（-1：出错）
 */
int Socket::send_to_buff(const unsigned char *data, const unsigned int size)
{
	if(!data || !size)
	{
		log::_ERROR_LOG("发送数据到缓冲区时数据错误，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	StcByteBuff buffer;

	unsigned int _size = this->packet(data, size, buffer);
	if(_size)
	{
		/// 写入数据到发送缓冲区
		this->_M_wr_buff.write(buffer._ptr(), _size);

#ifdef _TOTO_DEBUG
		std::vector<char> tmp;
		tmp.resize(size + 1);
		bcopy(data, &tmp[0], size);
		tmp[size] = '\0';

		log::_DEBUG_LOG("发送数据(%s)到缓冲区成功，数据长度(%u)", &tmp[0], _size);
		this->_M_wr_buff.disp();
#endif
	}

	return size;
}

/**
 * \brief 直接发送数据
 * \param data：要发送的数据
 * \param size：要发送的数据长度
 * \return：发送数据的长度（-1：出错）
 */
int Socket::send_im(const unsigned char *data, const unsigned int size)
{
	if(!data || !size)
	{
		log::_ERROR_LOG("[Socket]发送数据到缓冲区时数据错误，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	StcByteBuff buffer;

	unsigned int _size = this->packet(data, size, buffer);
	if(_size)
	{
		/// 发送发送缓冲区中的数据
		int retcode = ::send(this->_M_sockfd, buffer._ptr(), _size, MSG_NOSIGNAL);
		if(retcode == -1)
		{
			log::_ERROR_LOG("[Socket]发送即时数据时出错，%s", __PRETTY_FUNCTION__);
			return -1;
		}

		return retcode;
	}

	return -1;
}


/**
 * @brief 接受数据到缓冲区
 * @return：接受数据的长度
 */
int Socket::recv_buff()
{
	/// 至少有一个缓冲单位
	this->_M_rd_buff.prewrite(_UNIT_BUFF_SIZE);

	/// 接收数据到接收缓冲区
	int retcode = ::recv(this->_M_sockfd, this->_M_rd_buff.wr_ptr(), this->_M_rd_buff.wr_size(), MSG_NOSIGNAL);
	if(retcode == -1)
	{
		log::_ERROR_LOG("接收数据时出错，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	/// 整理接收缓冲区的写入端
	this->_M_rd_buff.wr_shiftout(retcode);

#ifdef _TOTO_DEBUG
	log::_DEBUG_LOG("接到数据，长度 [%u] 字节", retcode);
	this->_M_rd_buff.disp();
#endif
	return retcode;
}

/**
 * @brief 从缓冲区中取数据
 * @param data：数据缓冲区
 * @param size：数据缓冲区的长度
 * @return：返回从缓冲区中读出的数据长度
 */
int Socket::recv_from_buff(unsigned char *data, const unsigned int size)
{
	if(!data || !size)
	{
		log::_ERROR_LOG("读取接收缓冲区数据出错，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	if(this->_M_rd_buff.rd_size() > 0)
	{
		StcByteBuff buffer;
		unsigned int _size = this->unpacket(this->_M_rd_buff.rd_ptr(), this->packetLen(this->_M_rd_buff.rd_ptr()), buffer);
		if(_size && _size <= size)
		{
			bcopy(buffer._ptr(), data, _size);
			this->_M_rd_buff.rd_shiftout(_size);
			return size;
		}
	}

	return 0;
}

/**
 * @brief 加入EPOLL事件
 * @param epollfd：epoll描述符
 * @param events：事件
 * @param ptr：操作参数
 */
int Socket::addEpoll(int epollfd, __uint32_t events, void* ptr)
{
	struct epoll_event event;
	event.data.ptr = ptr;
	event.events = events;

	if(epoll_ctl(epollfd, EPOLL_CTL_ADD, this->_M_sockfd, &event) == -1)
	{
		log::_ERROR_LOG("加入epoll事件错误，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	return 0;
}

/**
 * @brief 删除EPOLL事件
 * @param epollfd：epoll描述符
 * @param events：事件
 */
int Socket::delEpoll(int epollfd, __uint32_t events)
{
	struct epoll_event event;
	event.data.ptr = NULL;
	event.events = events;

	if(epoll_ctl(epollfd, EPOLL_CTL_DEL, this->_M_sockfd, &event) == -1)
	{
		log::_ERROR_LOG("删除epoll事件错误，%s", __PRETTY_FUNCTION__);
		return -1;
	}

	return 0;
}

